#include <iostream>
#include <vector>
#include <functional>
#include <map>
#include <string>

#define connect(signal, slot) Signal::GolbalInstance()->Connect(signal, slot)
#define disconnect(signal, slot) Signal::GolbalInstance()->Disconnect(signal, slot)
#define emit(signal, arg) Signal::GolbalInstance()->EmitSignal(signal, arg)

using FuncArray = std::vector<std::function<void(void*)>>;

class Signal
{
public:
    static Signal *GolbalInstance()
    {
        static Signal s;
        return &s;
    }
    void Connect(const std::string& signal, const std::function<void(void*)> & func)
    {
        auto ite = callbacks.find(signal);
        if(ite != callbacks.end())
        {
            ite->second.push_back(func);
        }
        else
        {
            FuncArray arr;
            arr.push_back(func);
            callbacks.insert({signal, arr});

        }
    }
    void Disconnect(const std::string& signal, const std::function<void(void*)> &func)
    {
        auto ite = callbacks.find(signal);
        if(ite == callbacks.end())
        {
            return;
        }
        auto &v= ite->second;
        for(auto vecite = v.begin(); vecite != v.end(); vecite++)
        {
            if(func.target_type() == vecite->target_type())
            {
                v.erase(vecite);
                return;
            }
        }
    }
    void EmitSignal(const std::string& signal, void *arg)
    {
        auto ite = callbacks.find(signal);
        if(ite == callbacks.end())
        {
            return;
        }
        for(auto &func :ite->second)
        {
            func(arg);
        }
    }

private:
    std::map<std::string, FuncArray> callbacks;//回调列表
};

void func1(void* arg)
{
    std::cout<<"网络初始化\n";
    emit("网络启动", nullptr);
}

void func2(void* arg)
{
    std::cout<<"数据库初始化\n";
    emit("数据库启动", nullptr);
}


void func3(void* arg)
{
    std::cout<<"界面初始化\n";
    emit("界面启动", nullptr);
}
void func4(void* arg)
{
    std::cout<<"系统初始化成功\n";
}

int main()
{
    connect("网络启动", func2);
    connect("数据库启动", func3);
    connect("界面启动", func4);

    func1(nullptr);
    return 0;
}